<template>
  <div class="plating-line" ref="container">
    <canvas
      ref="canvas"
      :width="width"
      :height="height"
      @mousemove="handleCanvasMouseMove"
      @mouseleave="handleCanvasMouseLeave"
      @dblclick="handleCanvasDbClick"
    ></canvas>

    <div
      v-if="activeTooltip && activeTooltip.params"
      class="tooltip"
      :style="tooltipStyle"
    >
      <div class="tooltip-title">{{ activeTooltip.name }}</div>
      <div class="tooltip-content">
        <div class="tooltip-item">
          <span class="label">液体:</span>
          <span class="value">{{
            (activeTooltip.liquid && activeTooltip.liquid.name) || '-'
          }}</span>
        </div>
        <div class="tooltip-item">
          <span class="label">工件号:</span>
          <span class="value">{{
            activeTooltip.params.workpieceNum.value
          }}</span>
        </div>
        <div class="tooltip-item">
          <span class="label">挂组ID:</span>
          <span class="value">{{
            activeTooltip.params.hangGroupID.value
          }}</span>
        </div>
        <div class="tooltip-item">
          <span class="label">设定时间:</span>
          <span class="value">{{ activeTooltip.params.setTime.value }}</span>
        </div>
        <div class="tooltip-item">
          <span class="label">工作计时:</span>
          <span class="value">{{ activeTooltip.params.workTime.value }}</span>
        </div>
        <div class="tooltip-item">
          <span class="label">接液开关:</span>
          <span class="value">{{
            activeTooltip.params.liquidConSwitch.value ? '开' : '关'
          }}</span>
        </div>
        <div class="tooltip-item">
          <span class="label">倒水开关:</span>
          <span class="value">{{
            activeTooltip.params.dischargeSwitch.value ? '开' : '关'
          }}</span>
        </div>
        <div
          class="tooltip-item"
          v-if="activeTooltip.params.doorSwitch !== undefined"
        >
          <span class="label">门盖开关:</span>
          <span class="value">{{
            activeTooltip.params.doorSwitch.value ? '开' : '关'
          }}</span>
        </div>

        <div
          v-if="activeTooltip.params.temperature !== undefined"
          class="tooltip-item"
          :class="{
            'param-warning': isParamWarning(activeTooltip.params, 'temperature')
          }"
        >
          <span class="label">温度:</span>
          <span class="value">
            {{ activeTooltip.params.temperature.value
            }}{{
              (activeTooltip.params.temperatureLimit &&
                activeTooltip.params.temperatureLimit.unit) ||
                '℃'
            }}
            <span class="limit" v-if="activeTooltip.params.temperatureLimit">
              ({{ activeTooltip.params.temperatureLimit.min }}-{{
                activeTooltip.params.temperatureLimit.max
              }}{{ activeTooltip.params.temperatureLimit.unit || '' }})
            </span>
          </span>
        </div>

        <div
          v-if="activeTooltip.params.liquidLevel !== undefined"
          class="tooltip-item"
          :class="{
            'param-warning': isParamWarning(activeTooltip.params, 'liquidLevel')
          }"
        >
          <span class="label">液位:</span>
          <span class="value">
            {{ activeTooltip.params.liquidLevel.value }}
            <span class="limit" v-if="activeTooltip.params.levelLimit">
              ({{ activeTooltip.params.levelLimit.min }}-{{
                activeTooltip.params.levelLimit.max
              }}%)
            </span>
          </span>
        </div>

        <div
          v-if="
            activeTooltip.params.highLiquidLevel !== undefined &&
              activeTooltip.params.highLiquidLevel
          "
          class="tooltip-item"
        >
          <span class="label">液位:</span>
          <span class="value"> 高 </span>
        </div>

        <div
          v-if="
            activeTooltip.params.lowLiquidLevel !== undefined &&
              activeTooltip.params.lowLiquidLevel.value
          "
          class="tooltip-item"
        >
          <span class="label">液位:</span>
          <span class="value"> 低 </span>
        </div>

        <div
          v-if="activeTooltip.params.current !== undefined"
          class="tooltip-item"
          :class="{
            'param-warning': isParamWarning(activeTooltip.params, 'current')
          }"
        >
          <span class="label">电流:</span>
          <span class="value">
            {{ activeTooltip.params.current.value
            }}{{
              (activeTooltip.params.currentLimit &&
                activeTooltip.params.currentLimit.unit) ||
                ''
            }}
            <span class="limit" v-if="activeTooltip.params.currentLimit">
              ({{ activeTooltip.params.currentLimit.min }}-{{
                activeTooltip.params.currentLimit.max
              }}{{ activeTooltip.params.currentLimit.unit || '' }})
            </span>
          </span>
        </div>

        <div
          v-if="activeTooltip.params.voltage !== undefined"
          class="tooltip-item"
          :class="{
            'param-warning': isParamWarning(activeTooltip.params, 'voltage')
          }"
        >
          <span class="label">电压:</span>
          <span class="value">
            {{ activeTooltip.params.voltage.value
            }}{{
              (activeTooltip.params.voltageLimit &&
                activeTooltip.params.voltageLimit.unit) ||
                ''
            }}
            <span class="limit" v-if="activeTooltip.params.voltageLimit">
              ({{ activeTooltip.params.voltageLimit.min }}-{{
                activeTooltip.params.voltageLimit.max
              }}{{ activeTooltip.params.voltageLimit.unit || '' }})
            </span>
          </span>
        </div>

        <div
          v-if="activeTooltip.params.ph !== undefined"
          class="tooltip-item"
          :class="{
            'param-warning': isParamWarning(activeTooltip.params, 'ph')
          }"
        >
          <span class="label">pH值:</span>
          <span class="value">
            {{ activeTooltip.params.ph.value }}
            <span class="limit" v-if="activeTooltip.params.phLimit">
              ({{ activeTooltip.params.phLimit.min }}-{{
                activeTooltip.params.phLimit.max
              }})
            </span>
          </span>
        </div>

        <div
          v-if="activeTooltip.params.conductivity !== undefined"
          class="tooltip-item"
          :class="{
            'param-warning': isParamWarning(
              activeTooltip.params,
              'conductivity'
            )
          }"
        >
          <span class="label">电导率:</span>
          <span class="value">
            {{ activeTooltip.params.conductivity.value }}
            <span class="limit" v-if="activeTooltip.params.conductivityLimit">
              ({{ activeTooltip.params.conductivityLimit.min }}-{{
                activeTooltip.params.conductivityLimit.max
              }})
            </span>
          </span>
        </div>

        <div class="tooltip-item">
          <span class="label">状态:</span>
          <span class="value" :class="'status-' + activeTooltip.status">
            {{ $srv.getI18nBySrv(activeTooltip.status) }}
          </span>
        </div>
      </div>
    </div>

    <slot-para-set-modal
      ref="slotParaSetModal"
      @on-save="handleSaveParam"
    ></slot-para-set-modal>
  </div>
</template>

<script lang="ts">
import {
  ButtonConfig,
  CraneConfig,
  ProductionLineConfig,
  T_srv,
  TankAnimation,
  TankConfig,
  TankParamLimit,
  TankParams,
  vue,
  WorkpieceConfig,
  N_cStph,
  T_cmd,
  I_cmd
} from './config';
import SlotParaSetModal from './slotParaSetModal.vue';

@T_srv.comp({ components: { SlotParaSetModal } })
export default class PlatingLine extends vue {
  // 接收父组件传入的生产线配置
  @T_srv.prop({ required: true }) readonly config!: ProductionLineConfig;

  @T_srv.prop({ required: true }) cavansHeight: number;

  // 画布宽度
  private width: number = 2700;

  // 画布高度
  private height: number = 400;

  // Canvas 上下文
  private ctx: CanvasRenderingContext2D | null = null;

  // 工具提示相关属性
  private activeTooltip: TankConfig | null = null;

  // 当前激活的工具提示
  private tooltipStyle = {
    // 工具提示样式
    left: '0px',
    top: '0px'
  };

  // 3D 效果配置
  private readonly perspective = 0.3; // 3D 透视系数

  // 缩放比例
  private scale = 0.8;

  // 槽体状态颜色配置
  private readonly colors = {
    // 工作时绿色
    working: {
      main: '#4CAF50', // 工作状态主色
      side: '#388E3C', // 工作状态侧面色
      top: '#81C784', // 工作状态顶面色
      text: '#FFFFFF' // 工作状态字体颜色
    },
    // 空闲时蓝色
    idle: {
      main: '#2196F3', // 空闲状态主色
      side: '#1976D2', // 空闲状态侧面色
      top: '#64B5F6', // 空闲状态顶面色
      text: '#FFFFFF' // 空闲状态字体颜色
    },
    // 关闭时灰色
    closed: {
      main: '#9E9E9E', // 关闭状态主色
      side: '#757575', // 关闭状态侧面色
      top: '#BDBDBD', // 关闭状态顶面色
      text: '#212121'
    },
    // 报警时红色
    error: {
      main: '#F44336', // 错误状态主色
      side: '#D32F2F', // 错误状态侧面色
      top: '#E57373', // 错误状态顶面色
      text: '#FFFFFF' // 错误状态字体颜色
    },
    // 缓存位橙色
    cache: {
      main: '#FF9800', // 缓存位主色
      side: '#F57C00', // 缓存位侧面色
      top: '#FFB74D', // 缓存位顶面色
      text: '#212121'
    }
  };

  // 行车状态颜色配置
  private readonly craneColors = {
    idle: '#8c8c8c', // 空闲状态
    moving: '#1890ff', // 移动状态
    loading: '#faad14', // 装载状态
    unloading: '#52c41a' // 卸载状态
  };

  // 工件状态颜色配置
  private readonly workpieceColors = {
    waiting: '#1890ff', // 等待状态
    processing: '#1890ff', // 处理中状态
    finished: '#52c41a' // 完成状态
  };

  // 动画帧
  private animationFrame: number | null = null;

  // 行车移动速度
  private craneSpeed = 1;

  // 工件移动速度
  private workpieceSpeed = 1;

  // 容器默认宽度
  private containerWidth: number = 1200;

  // 槽体动画列表
  private tankAnimations: TankAnimation[] = [];

  // 闪烁持续时间（毫秒）
  private readonly FLASH_DURATION = 1500;

  // 保存事件处理函数引用以便清理
  private mouseMoveHandler: (event: MouseEvent) => void | null = null;

  private GT_command: I_cmd = new T_cmd();

  /**
   * 组件挂载时的初始化
   */
  mounted(): void {
    this.$nextTick(() => {
      const canvas = this.$refs.canvas as HTMLCanvasElement;
      this.ctx = canvas.getContext('2d');

      // 获取容器宽度
      const container = this.$el as HTMLElement;
      const containerWidth = container.clientWidth || window.innerWidth;

      // 设置canvas的实际尺寸
      canvas.width = containerWidth;
      canvas.height = 500;

      // 更新组件的宽度和高度属性
      this.width = containerWidth;
      this.height = this.cavansHeight;

      // 初始化布局
      this.recalculateLayout();
      // 启动动画循环
      this.startAnimation();
    });
    this.initContainer();
  }

  /**
   * 组件销毁前的清理工作
   */
  beforeDestroy(): void {
    const canvas = this.$refs.canvas as HTMLCanvasElement;
    if (this.mouseMoveHandler) {
      canvas.removeEventListener('mousemove', this.mouseMoveHandler);
    }
    canvas.removeEventListener('mouseleave', () => {
      this.activeTooltip = null;
    });
    window.removeEventListener('resize', this.handleResize);

    if (this.animationFrame) {
      cancelAnimationFrame(this.animationFrame);
    }
  }

  /**
   * 监听配置变化，重新绘制生产线
   */
  // @T_srv.watch('config', { deep: true })
  // onConfigChange() {
  //   this.drawProductionLine();
  // }

  /**
   * 初始化容器尺寸和布局
   */
  private initContainer(): void {
    const container = this.$el as HTMLElement;
    this.containerWidth = container.clientWidth || 1200; // 获取容器宽度
    this.width = this.containerWidth;

    this.recalculateLayout(); // 计算布局

    // 监听窗口大小变化
    window.addEventListener('resize', () => {
      const newWidth = (this.$el as HTMLElement).clientWidth;
      if (newWidth !== this.containerWidth) {
        this.containerWidth = newWidth;
        this.width = newWidth;
        this.height = this.cavansHeight;
        this.recalculateLayout(); // 重新计算布局
      }
    });
  }

  /**
   * 初始化 Canvas 上下文
   */
  private initCanvas(): void {
    const canvas = this.$refs.canvas as HTMLCanvasElement;
    this.ctx = canvas.getContext('2d');
    if (!this.ctx) {
      console.error('Failed to get canvas context');
      return;
    }
    this.ctx.font = '12px Arial'; // 设置默认字体
  }

  /**
   * 添加鼠标事件监听
   */
  private addEventListeners(): void {
    const canvas = this.$refs.canvas as HTMLCanvasElement;

    // 使用箭头函数确保this指向正确
    canvas.addEventListener('mousemove', (event: MouseEvent) => {
      const rect = canvas.getBoundingClientRect();
      const x = event.clientX - rect.left;
      const y = event.clientY - rect.top;

      // 查找鼠标下方的槽体
      const hoveredTank = this.config.tanks.find(tank => {
        return (
          x >= tank.position.x &&
          x <= tank.position.x + tank.width &&
          y >= tank.position.y &&
          y <= tank.position.y + tank.height
        );
      });

      if (hoveredTank) {
        this.activeTooltip = hoveredTank;
        this.tooltipStyle = {
          left: `${event.clientX + 10}px`,
          top: `${event.clientY + 10}px`
        };
      } else {
        this.activeTooltip = null;
      }
    });

    canvas.addEventListener('mouseleave', () => {
      this.activeTooltip = null;
    });
  }

  /**
   * 移除事件监听
   */
  private removeEventListeners(): void {
    const canvas = this.$refs.canvas as HTMLCanvasElement;
    canvas.removeEventListener('mousemove', this.handleMouseMove);
    canvas.removeEventListener('mouseleave', this.handleMouseLeave);
  }

  /**
   * 处理鼠标移动事件
   * @param event 鼠标事件对象
   */
  private handleMouseMove = (event: MouseEvent): void => {
    const canvas = this.$refs.canvas as HTMLCanvasElement;
    const rect = canvas.getBoundingClientRect();

    // 计算鼠标在canvas中的实际位置，需要考虑缩放比例
    const scaleX = canvas.width / rect.width;
    const scaleY = canvas.height / rect.height;

    const x = (event.clientX - rect.left) * scaleX;
    const y = (event.clientY - rect.top) * scaleY;

    // 查找鼠标下方的槽体
    const hoveredTank = this.config.tanks.find(tank => {
      const tankRight = tank.position.x + tank.width;
      const tankBottom = tank.position.y + tank.height;

      return (
        x >= tank.position.x &&
        x <= tankRight &&
        y >= tank.position.y &&
        y <= tankBottom
      );
    });

    if (hoveredTank) {
      this.activeTooltip = hoveredTank;

      // 设置工具提示位置
      const tooltipX = event.clientX + 10;
      const tooltipY = event.clientY + 10;

      // 防止提示框超出视窗
      const maxX = window.innerWidth - 250;
      const maxY = window.innerHeight - 200;

      this.tooltipStyle = {
        left: `${Math.min(tooltipX, maxX)}px`,
        top: `${Math.min(tooltipY, maxY)}px`
      };
    } else {
      this.activeTooltip = null;
    }
  };

  /**
   * 处理鼠标离开事件
   */
  private handleMouseLeave = (): void => {
    this.activeTooltip = null;
  };

  /**
   * 根据坐标查找槽体
   * @param x 横坐标
   * @param y 纵坐标
   * @returns 找到的槽体或 null
   */
  private findTankAtPosition(x: number, y: number): TankConfig | null {
    return (
      this.config.tanks.find(tank => {
        const { x: tankX, y: tankY } = tank.position;
        // 检查坐标是否在槽体范围内
        return (
          x >= tankX &&
          x <= tankX + tank.width &&
          y >= tankY &&
          y <= tankY + tank.height
        );
      }) || null
    );
  }

  /**
   * 绘制槽体
   * @param tank 槽体配置
   */
  private drawTank(tank: TankConfig): void {
    if (!this.ctx) return;

    const { x, y } = tank.position;
    const { width, height, depth } = tank;
    const colors = this.colors[tank.status];

    // this.ctx.save(); // 保存当前绘图状态

    // 绘制主体
    this.drawMain(tank, colors.main);

    // 绘制侧面
    this.drawSide(tank, colors.side);

    // 绘制顶面
    this.drawTop(tank, colors.top);

    // 绘制文本信息
    this.drawText(tank);

    // 检查是否正在动画中
    const animation = this.tankAnimations.find(a => a.tankId === tank.id);
    if (animation) {
      const elapsed = Date.now() - animation.startTime;
      if (!animation.continuous && elapsed >= animation.duration) {
        // 非持续动画结束时，移除动画状态
        this.tankAnimations = this.tankAnimations.filter(
          a => a.tankId !== tank.id
        );
      } else {
        // 计算闪烁效果
        const flashAlpha = Math.abs(Math.sin(elapsed / 200));
        this.ctx.strokeStyle = '#48cf5f';
        this.ctx.lineWidth = 4;
        this.ctx.globalAlpha = flashAlpha;
        this.ctx.strokeRect(x - 2, y - 2, width + 4, height + 4);
        this.ctx.globalAlpha = 1; // 重置透明度
      }
    }

    // 绘制液体
    // if (tank.params?.liquidLevel) {
    //   const liquidHeight = height * (tank.params.liquidLevel.value as number);
    //   const liquidY = y + height - liquidHeight;

    //   // 绘制液体主体
    //   this.ctx.fillStyle = tank.liquid.color;
    //   this.ctx.fillRect(x, liquidY, width, liquidHeight);

    //   // 绘制液体的3D效果
    //   this.ctx.fillStyle = tank.liquid.color;
    //   this.ctx.beginPath();
    //   this.ctx.moveTo(x + width, liquidY);
    //   this.ctx.lineTo(
    //     x + width + depth * this.perspective,
    //     liquidY - depth * this.perspective
    //   );
    //   this.ctx.lineTo(
    //     x + width + depth * this.perspective,
    //     y + height - depth * this.perspective
    //   );
    //   this.ctx.lineTo(x + width, y + height);
    //   this.ctx.closePath();
    //   this.ctx.fill();
    // }

    // this.ctx.restore();
  }

  /**
   * 绘制槽体主体
   * @param tank 槽体配置
   * @param color 主体颜色
   */

  private drawMain(tank: TankConfig, color: string): void {
    if (!this.ctx) return;
    const { x, y } = tank.position;
    const { width, height, depth } = tank;

    this.ctx.beginPath();
    this.ctx.fillStyle = color;
    this.ctx.strokeStyle = '#1890ff';
    this.ctx.lineWidth = 2;
    this.ctx.roundRect(x, y, width, height, 4);
    this.ctx.fill();
    this.ctx.stroke();
  }

  /**
   * 绘制槽体侧面
   * @param tank 槽体配置
   * @param color 侧面颜色
   */
  private drawSide(tank: TankConfig, color: string): void {
    if (!this.ctx) return;
    const { x, y } = tank.position;
    const { width, height, depth } = tank;

    this.ctx.beginPath();
    this.ctx.fillStyle = color;
    this.ctx.moveTo(x + width, y);
    this.ctx.lineTo(
      x + width + depth * this.perspective,
      y - depth * this.perspective
    );
    this.ctx.lineTo(
      x + width + depth * this.perspective,
      y + height - depth * this.perspective
    );
    this.ctx.lineTo(x + width, y + height);

    this.ctx.closePath();
    this.ctx.fill();
    this.ctx.stroke();
  }

  /**
   * 绘制槽体顶面
   * @param tank 槽体配置
   * @param color 顶面颜色
   */
  private drawTop(tank: TankConfig, color: string): void {
    if (!this.ctx) return;
    const { x, y } = tank.position;
    const { width, depth } = tank;

    this.ctx.beginPath();
    // this.ctx.fillStyle = color;
    this.ctx.fillStyle = this.colors[tank.status].top;

    this.ctx.moveTo(x, y);
    this.ctx.lineTo(x + depth * this.perspective, y - depth * this.perspective);
    this.ctx.lineTo(
      x + width + depth * this.perspective,
      y - depth * this.perspective
    );
    this.ctx.lineTo(x + width, y);
    this.ctx.closePath();
    this.ctx.fill();
    this.ctx.stroke();
  }

  /**
   * 绘制槽内液体
   * @param tank 槽体配置
   */
  private drawLiquid(tank: TankConfig): void {
    if (!this.ctx) return;
    const { x, y } = tank.position;
    const { width, height, depth } = tank;
    const liquidHeight = height * tank.liquid.level;
    const liquidY = y + height - liquidHeight;

    // 液体正面
    this.ctx.beginPath();
    const gradient = this.ctx.createLinearGradient(x, liquidY, x, y + height);
    gradient.addColorStop(0, `${tank.liquid.color}cc`); // 80% 透明度
    gradient.addColorStop(1, `${tank.liquid.color}66`); // 40% 透明度
    this.ctx.fillStyle = gradient;
    this.ctx.roundRect(x + 4, liquidY, width - 8, liquidHeight - 4, 2);
    this.ctx.fill();

    // 液体顶面
    this.ctx.beginPath();
    this.ctx.fillStyle = `${tank.liquid.color}cc`;
    this.ctx.moveTo(x + 4, liquidY);
    this.ctx.lineTo(
      x + 4 + depth * this.perspective,
      liquidY - depth * this.perspective
    );
    this.ctx.lineTo(
      x + width - 4 + depth * this.perspective,
      liquidY - depth * this.perspective
    );
    this.ctx.lineTo(x + width - 4, liquidY);
    this.ctx.closePath();
    this.ctx.fill();
  }

  /**
   * 绘制槽体文本信息
   * @param tank 槽体配置
   */
  private drawText(tank: TankConfig): void {
    if (!this.ctx) return;
    const { x, y } = tank.position;
    const { width, height } = tank;

    this.ctx.textAlign = 'left';
    const padding = 5;
    const leftPadding = x + padding;
    let currentY = y + padding + 14;

    // 绘制工位名称 - 大号字体，居中
    this.ctx.font = 'bold 12px Arial';
    this.ctx.fillStyle = this.colors[tank.status].text;
    this.ctx.textAlign = 'center';
    this.ctx.fillText(tank.workName, x + width / 2, currentY);
    currentY += 16;

    // 绘制槽体名称 - 大号字体，居中
    this.ctx.font = 'bold 12px Arial';
    this.ctx.fillStyle = this.colors[tank.status].text;
    this.ctx.textAlign = 'center';
    this.ctx.fillText(tank.name, x + width / 2, currentY);
    currentY += 16;

    // 恢复左对齐，缩小字体
    this.ctx.textAlign = 'left';
    this.ctx.font = '11px Arial';

    // 绘制参数，带有状态颜色指示
    const drawParameter = (label: string, value: string) => {
      this.ctx!.fillStyle = this.colors[tank.status].text;
      this.ctx!.fillText(label, leftPadding, currentY);
      this.ctx!.textAlign = 'right';
      this.ctx!.fillText(value, x + width - padding, currentY);
      this.ctx!.textAlign = 'left';
      currentY += 14;
    };

    // 绘制各项参数
    drawParameter('工件号：', `${tank.params.workpieceNum.value}`);

    // drawParameter('挂组ID：', `${tank.params.hangGroupID.value}`);

    // drawParameter('接液', `${tank.params.liquidConSwitch ? '开' : '关'}`);
    // drawParameter('倒水', `${tank.params.dischargeSwitch ? '开' : '关'}`);

    drawParameter('设定时间', `${tank.params.setTime.value}`);
    drawParameter('工作计时', `${tank.params.workTime.value}`);

    if (tank.params.temperature !== undefined) {
      drawParameter(
        '温度:',
        `${tank.params.temperature.value as number}${(tank.params
          .temperatureLimit &&
          tank.params.temperatureLimit.unit) ||
          ''}`
      );
    }

    let level = '';
    if (tank.params.liquidLevel !== undefined) {
      level = `${tank.params.liquidLevel.value as number}`;
    } else {
      level =
        tank.params.highLiquidLevel !== undefined &&
        tank.params.highLiquidLevel.value
          ? '高'
          : tank.params.lowLiquidLevel !== undefined &&
            tank.params.lowLiquidLevel.value
          ? '低'
          : '';
    }
    if (level !== '') {
      drawParameter('液位:', level);
    }

    if (tank.params.current !== undefined) {
      drawParameter(
        '电流:',
        `${tank.params.current.value as number}${(tank.params.currentLimit &&
          tank.params.currentLimit.unit) ||
          ''}`
      );
    }
    if (tank.params.voltage !== undefined) {
      drawParameter(
        '电压:',
        `${tank.params.voltage.value as number}${(tank.params.voltageLimit &&
          tank.params.voltageLimit.unit) ||
          ''}`
      );
    }
    if (tank.params.ph !== undefined) {
      drawParameter('pH值:', `${tank.params.ph.value as number}`);
    }
    if (tank.params.conductivity !== undefined) {
      drawParameter('电导率:', `${tank.params.conductivity.value as number}`);
    }
    if (tank.params.doorSwitch !== undefined) {
      drawParameter('门盖', `${tank.params.doorSwitch.value ? '开' : '关'}`);
    }
  }

  /**
   * 双击槽体，弹出参数设置对话框
   * @param event 鼠标事件
   */
  private handleCanvasDbClick(event: MouseEvent): void {
    const canvas = this.$refs.canvas as HTMLCanvasElement;

    const rect = canvas.getBoundingClientRect();
    const mouseX = event.clientX - rect.left;
    const mouseY = event.clientY - rect.top;

    // 检查是否点击了槽体
    const clickedTank = this.config.tanks.find(tank => {
      return (
        mouseX >= tank.position.x * this.scale &&
        mouseX <= (tank.position.x + tank.width) * this.scale &&
        mouseY >= tank.position.y * this.scale &&
        mouseY <= (tank.position.y + tank.height) * this.scale
      );
    });

    if (clickedTank) {
      (this.$refs.slotParaSetModal as any).show(clickedTank);
    }
  }

  /**
   * 启动动画循环
   */
  private startAnimation(): void {
    const animate = () => {
      this.updateCranePosition(); // 更新行车位置
      this.updateWorkpiecePosition(); // 更新工件位置
      this.drawProductionLine(); // 重绘生产线
      this.animationFrame = requestAnimationFrame(animate);
    };
    animate();
  }

  /**
   * 计算行车在指定槽位的显示位置
   * @param targetX 目标X坐标
   * @param tankId 目标槽体ID
   * @returns 映射后的显示位置
   */
  private calculateCraneDisplayPosition(
    targetX: number,
    tankId?: number
  ): { x: number; y: number } {
    // 如果没有指定槽体ID，返回默认位置
    if (!tankId) {
      return {
        x: targetX,
        y: this.config.startPosition.y - 115
      };
    }

    // 找到目标槽体
    const targetTank = this.config.tanks.find(t => t.id === tankId);
    if (!targetTank) {
      return {
        x: targetX,
        y: this.config.startPosition.y - 115
      };
    }

    // 计算槽体所在行
    const rowIndex = Math.floor((targetTank.id - 1) / this.config.tanksPerRow);
    const y =
      this.config.startPosition.y +
      rowIndex * (this.config.tanks[0].height + this.config.rowGap) -
      115;

    // 计算在当前行中的X坐标
    const columnIndex = (targetTank.id - 1) % this.config.tanksPerRow;
    const x =
      this.config.startPosition.x +
      columnIndex * (targetTank.width + this.config.tankGap);

    return { x, y };
  }

  /**
   * 移动行车到指定位置
   */
  public moveCraneTo(craneId: number, targetTankId?: number): void {
    const crane = this.config.cranes.find(c => c.id === craneId);
    if (!crane) {
      console.warn(`未找到ID为${craneId}的行车`);
      return;
    }

    // 找到目标槽体
    const targetTank = targetTankId
      ? this.config.tanks.find(t => t.id === targetTankId)
      : null;
    if (targetTank) {
      // 如果行车当前有关联的槽体，停止其闪烁
      if (crane.load?.currentTankId) {
        const currentTankId = crane.load.currentTankId;
        this.tankAnimations = this.tankAnimations.filter(
          a => a.tankId !== currentTankId
        );
      }

      // 计算目标行号和位置
      const targetRow = Math.floor(
        (targetTank.id - 1) / this.config.tanksPerRow
      );
      const currentRow = Math.floor(
        (crane.position.y + 115 - this.config.startPosition.y) /
          (this.config.tanks[0].height + this.config.rowGap)
      );

      // 计算目标Y坐标
      const targetY =
        this.config.startPosition.y +
        targetRow * (this.config.tanks[0].height + this.config.rowGap) -
        115;

      // 计算槽体中心X坐标
      const targetCenterX =
        targetTank.position.x + (targetTank.width - crane.width) / 2;

      if (targetRow !== currentRow) {
        // 如果是换行，停止所有闪烁
        this.tankAnimations = [];
      }

      // 更新行车位置和状态
      if (targetRow !== currentRow) {
        crane.position = {
          x: targetCenterX,
          y: targetY
        };
      } else {
        crane.position.y = targetY;
      }

      crane.targetPosition = {
        x: targetCenterX,
        y: targetY
      };
      crane.status = 'moving';

      // 更新工件信息
      if (!crane.load) {
        crane.load = {
          id: -1,
          name: '',
          width: 0,
          height: 0,
          position: {
            x: crane.position.x,
            y: targetY + crane.height
          },
          status: 'waiting',
          currentTankId: targetTankId
        };
      } else {
        crane.load.currentTankId = targetTankId;
        crane.load.position = {
          x: crane.position.x + 15,
          y: targetY + crane.height + 30
        };
      }
    }
  }

  /**
   * 更新行车位置
   */
  private updateCranePosition(): void {
    const { cranes } = this.config;

    cranes.forEach(crane => {
      if (crane.targetPosition && crane.status === 'moving') {
        const dx = crane.targetPosition.x - crane.position.x;
        const distance = Math.abs(dx);

        if (distance < this.craneSpeed) {
          // 到达目标位置
          crane.position = { ...crane.targetPosition };
          crane.status = 'idle';

          // 到达目标位置时，开始目标槽体闪烁
          if (crane.load?.currentTankId) {
            // 找到目标槽体
            const targetTank = this.config.tanks.find(
              t => t.id === crane.load.currentTankId
            );
            if (targetTank) {
              // 移除当前行车相关的闪烁动画
              this.tankAnimations = this.tankAnimations.filter(a => {
                // 保留其他行车的闪烁动画
                const otherCraneTank = this.config.cranes.some(
                  c => c.id !== crane.id && c.load?.currentTankId === a.tankId
                );
                return otherCraneTank;
              });

              if (targetTank.status === 'working') {
                // 添加新的闪烁动画
                this.tankAnimations.push({
                  tankId: targetTank.id,
                  startTime: Date.now(),
                  duration: this.FLASH_DURATION,
                  continuous: true,
                  craneId: crane.id // 记录是哪个行车触发的闪烁
                });
              }
            }
          }
        } else {
          // 继续移动
          const nextX = crane.position.x + Math.sign(dx) * this.craneSpeed;
          crane.position = {
            x: nextX,
            y: crane.targetPosition.y
          };

          // 更新工件位置
          if (crane.load) {
            crane.load.position = {
              x: nextX + 15,
              y: crane.position.y + crane.height + 30
            };
          }
        }
      }
    });
  }

  /**
   * 更新工件位置
   */
  private updateWorkpiecePosition(): void {
    const { cranes } = this.config;
    cranes.forEach(crane => {
      if (
        crane.load &&
        crane.status !== 'moving' &&
        crane.load.status === 'processing'
      ) {
        const y = crane.load.position.y;
        const targetY = crane.load.targetY;
        const dy = targetY === undefined ? 1 : targetY - y;

        if (Math.abs(dy) === this.workpieceSpeed) {
          // 到达目标位置
          crane.load.position.y = targetY;
          crane.load.status = 'waiting';
        } else {
          // 继续移动
          const nextY =
            dy > 0 ? y + this.workpieceSpeed : y - this.workpieceSpeed;
          crane.load.position.y = nextY;
        }
      }
    });
  }

  /**
   * 绘制行车
   * @param crane 行车配置
   */
  private drawCrane(crane: CraneConfig): void {
    if (!this.ctx) return;

    const { x, y } = crane.position;

    const { width, height } = crane;

    this.ctx.save();

    // 添加阴影效果
    this.ctx.shadowColor = 'rgba(0, 0, 0, 0.2)';
    this.ctx.shadowBlur = 10;
    this.ctx.shadowOffsetX = 5;
    this.ctx.shadowOffsetY = 5;

    // 绘制行车主体
    this.ctx.fillStyle = this.craneColors[crane.status];
    this.ctx.strokeStyle = '#595959';
    this.ctx.lineWidth = 2;
    this.ctx.beginPath();
    this.ctx.roundRect(x, y, width, height, 4);
    this.ctx.fill();
    this.ctx.stroke();

    // 绘制行车编号
    this.ctx.font = '12px Arial';
    this.ctx.fillStyle = '#fff';
    this.ctx.textAlign = 'center';
    this.ctx.fillText(crane.name, x + width / 2, y + height / 2);

    // 绘制吊钩
    if (crane.load) {
      this.ctx.beginPath();
      this.ctx.strokeStyle = '#595959';
      this.ctx.lineWidth = 2;
      this.ctx.moveTo(x + width / 2, y + height);
      this.ctx.lineTo(x + width / 2, y + height + 30);
      this.ctx.stroke();
    }

    // 绘制碰撞警告
    if (crane.collisionWarning) {
      this.ctx.save();
      this.ctx.strokeStyle = '#ff4d4f';
      this.ctx.lineWidth = 3;
      this.ctx.setLineDash([5, 5]);
      this.ctx.strokeRect(x - 5, y - 5, width + 10, height + 10);
      this.ctx.font = '14px Arial';
      this.ctx.fillStyle = '#ff4d4f';
      this.ctx.fillText('⚠️ 碰撞警告', x + width / 2, y - 15);
      this.ctx.restore();
    }

    this.ctx.restore();
  }

  /**
   * 绘制工件
   * @param workpiece 工件配置
   */
  private drawWorkpiece(workpiece: WorkpieceConfig): void {
    // 确保 Canvas 上下文存在
    if (!this.ctx) return;

    // 获取工件的位置和尺寸信息
    const { x, y } = workpiece.position; // x,y 是工件左上角的坐标
    const { width, height } = workpiece; // width,height 是工件的宽度和高度

    // 保存当前绘图上下文的状态（颜色、样式等）
    this.ctx.save();

    // 设置阴影效果
    this.ctx.shadowColor = 'rgba(0, 0, 0, 0.2)'; // 设置阴影颜色为半透明黑色
    this.ctx.shadowBlur = 5; // 设置阴影的模糊程度
    this.ctx.shadowOffsetX = 2; // 设置阴影在X轴的偏移量
    this.ctx.shadowOffsetY = 2; // 设置阴影在Y轴的偏移量

    // 绘制工件主体
    this.ctx.fillStyle = this.workpieceColors[workpiece.status]; // 根据工件状态设置填充颜色
    this.ctx.strokeStyle = '#595959'; // 设置边框颜色
    this.ctx.lineWidth = 1; // 设置边框宽度

    // 开始绘制路径
    this.ctx.beginPath();
    // 绘制圆角矩形，参数：x, y, width, height, 圆角半径
    this.ctx.roundRect(x, y, width, height, 2);
    this.ctx.fill(); // 填充矩形
    this.ctx.stroke(); // 绘制边框

    // 绘制工件名称
    this.ctx.fillStyle = '#fff'; // 设置文字颜色为白色
    this.ctx.font = '10px Arial'; // 设置字体大小和字体
    this.ctx.textAlign = 'center'; // 设置文字水平居中对齐
    // 绘制文字，参数：文本内容, x坐标(中心点), y坐标(基线)
    this.ctx.fillText(workpiece.name, x + width / 2, y + height / 2 + 4);

    // 恢复之前保存的绘图上下文状态
    this.ctx.restore();
  }

  /**
   * 绘制整个生产线
   */
  public drawProductionLine(): void {
    // 确保 Canvas 上下文存在
    if (!this.ctx) return;

    // 清空整个画布，准备重新绘制
    // clearRect 参数：左上角x, 左上角y, 宽度, 高度
    this.ctx.clearRect(0, 0, this.width, this.height);
    this.ctx.save();

    // 缩放0.8
    this.ctx.scale(this.scale, this.scale);

    // 绘制所有行的轨道
    this.config.rows.forEach(row => {
      // 开始新的绘制路径
      this.ctx!.beginPath();
      this.ctx!.strokeStyle = '#595959'; // 设置轨道颜色
      this.ctx!.lineWidth = 4; // 设置轨道线宽

      // 绘制主轨道（实线）
      this.ctx!.moveTo(
        // 移动画笔到起点
        this.config.startPosition.x, // 起点x坐标
        this.config.startPosition.y - 80 // 起点y坐标（槽体上方80像素）
      );
      this.ctx!.lineTo(
        // 直线到终点
        this.width - 50, // 终点x坐标（画布宽度减去50像素）
        this.config.startPosition.y - 80 // 终点y坐标
      );
      this.ctx!.stroke(); // 绘制轨道线条

      // 绘制虚拟轨道（虚线）- 用于其他行
      if (row.y !== this.config.startPosition.y) {
        this.ctx!.beginPath();
        this.ctx!.setLineDash([5, 5]); // 设置虚线样式：5像素线段，5像素间隔
        this.ctx!.moveTo(
          this.config.startPosition.x, // 虚线起点x坐标
          row.y - 80 // 虚线起点y坐标
        );
        this.ctx!.lineTo(
          this.width - 50, // 虚线终点x坐标
          row.y - 80 // 虚线终点y坐标
        );
        this.ctx!.stroke();
        this.ctx!.setLineDash([]); // 重置为实线
      }
    });

    // 按顺序绘制各个元素（确保正确的层叠顺序）

    // 1. 首先绘制所有槽体
    this.config.tanks.forEach(tank => this.drawTank(tank));

    // 2. 绘制未被行车携带的工件
    this.config.workpieces.forEach(workpiece => {
      // 检查工件是否正被行车携带
      const notBeingCarried = !this.config.cranes.some(
        crane => crane.load?.id === workpiece.id
      );
      // 只绘制未被携带的工件
      if (notBeingCarried) {
        this.drawWorkpiece(workpiece);
      }
    });

    // 3. 最后绘制行车及其携带的工件（确保显示在最上层）
    this.config.cranes.forEach(crane => {
      this.drawCrane(crane); // 绘制行车
      if (crane.load) {
        // 如果行车携带着工件
        this.drawWorkpiece(crane.load); // 绘制被携带的工件
      }
    });

    this.ctx.restore();
  }

  /**
   * 更新槽体状态
   * @param tankId 槽体ID
   * @param status 新状态
   * @param liquidLevel 液位值
   * @param temperature 温度值（可选）
   */
  public updateTankStatus(tanks: N_cStph.I_recTankInfo[]): void {
    tanks.forEach(it => {
      const tank = this.config.tanks.find(t => t.id === it.id);
      if (tank) {
        tank.params = it.params;
        if (it.params.liquidLevel !== undefined) {
          tank.liquid.level = it.params.liquidLevel.value as number;
        }
      }
    });
    this.drawProductionLine();
  }

  public loadWorkpiece(workpieceId: number): void {
    const crane = this.config.cranes.find(c => c.load?.id === workpieceId);
    if (crane && crane.status === 'idle') {
      crane.load = {
        id: workpieceId,
        name: `Part-${workpieceId}`,
        width: 25,
        height: 15,
        position: {
          x: crane.position.x,
          y: crane.position.y + crane.height
        },
        status: 'waiting'
      };
      crane.status = 'loading';
    }
  }

  public unloadWorkpiece(): void {
    const crane = this.config.cranes.find(c => c.load);
    if (crane) {
      crane.load = undefined;
      crane.status = 'idle';
    }
  }

  private recalculateLayout(): void {
    if (!this.ctx) return;

    const { tanks, tankGap, rowGap } = this.config;

    try {
      // 获取容器实际宽度
      const containerElement = this.$el as HTMLElement;
      this.containerWidth =
        containerElement.clientWidth / this.scale || window.innerWidth;

      // 使用第一个槽体的尺寸作为默认值
      const defaultTankWidth = tanks[0]?.width || 120;
      const defaultTankHeight = tanks[0]?.height || 160;

      // 只为没有设置尺寸的槽体设置默认尺寸
      // tanks.forEach(tank => {
      //   if (!tank.width) tank.width = defaultTankWidth;
      //   if (!tank.height) tank.height = defaultTankHeight;
      // });

      const tankTotalWidth = defaultTankWidth + tankGap;

      // 计算每行可以放置的槽数量
      const availableWidth = this.containerWidth - 100;
      const tanksPerRow = Math.floor(availableWidth / tankTotalWidth);

      // 确保每行至少1个槽体
      this.config.tanksPerRow = Math.max(1, tanksPerRow);

      // 计算需要的行数
      const rowCount = Math.ceil(tanks.length / this.config.tanksPerRow);

      // 更新槽体位置
      tanks.forEach((tank, index) => {
        const rowIndex = Math.floor(index / this.config.tanksPerRow);
        const columnIndex = index % this.config.tanksPerRow;
        const y =
          this.config.startPosition.y + rowIndex * (defaultTankHeight + rowGap);

        tank.position = {
          x: this.config.startPosition.x + columnIndex * tankTotalWidth,
          y
        };
      });

      // 更新行配置和轨道高度
      this.config.rows = Array.from({ length: rowCount }, (_, rowIndex) => {
        const rowY =
          this.config.startPosition.y + rowIndex * (defaultTankHeight + rowGap);
        return {
          y: rowY,
          railHeight: rowY - 80, // 轨道在槽体上方80像素
          crane: this.config.cranes[rowIndex] || this.config.cranes[0], // 分配行车
          startIndex: rowIndex * this.config.tanksPerRow,
          endIndex: Math.min(
            (rowIndex + 1) * this.config.tanksPerRow - 1,
            tanks.length - 1
          )
        };
      });

      // 更新轨道高度数组
      this.config.railHeights = this.config.rows.map(row => row.railHeight);

      // 更新行车位置到对应的轨道高度
      // this.config.cranes.forEach((crane, index) => {
      //   const row = this.config.rows[index] || this.config.rows[0];
      //   if (row) {
      //     crane.position.y = row.railHeight;
      //   }
      // });

      // 更新行车位置到实际工位
      // 1号行车默认在5号工位，2号行车默认在21号工位
      const crane1DefaultStation = this.config.tanks.find(it => it.id === 5)
        .position;

      const crane2DefaultStation = this.config.tanks.find(it => it.id === 21)
        .position;

      this.config.cranes[0].position = {
        x: crane1DefaultStation.x,
        y: crane1DefaultStation.y - 115
      };
      this.config.cranes[1].position = {
        x: crane2DefaultStation.x,
        y: crane2DefaultStation.y - 115
      };

      // 更新画布尺寸
      this.width = this.containerWidth;

      this.height = Math.max(
        this.cavansHeight,
        this.config.startPosition.y +
          rowCount * defaultTankHeight +
          rowGap * (rowCount - 1)
      );

      // this.height =
      //   this.config.startPosition.y +
      //   rowCount * defaultTankHeight +
      //   rowGap * (rowCount - 1);

      // 确保重新绘制
      this.$nextTick(() => {
        this.drawProductionLine();
      });
    } catch (error) {
      console.error('Error calculating layout:', error);
    }
  }

  /**
   * 停止槽体闪烁
   * @param tankId 槽体ID
   */
  private stopTankAnimation(tankId: number): void {
    this.tankAnimations = this.tankAnimations.filter(a => a.tankId !== tankId);
  }

  // 处理窗口大小变化
  private handleResize = (): void => {
    // const container = this.$el as HTMLElement;
    // const canvas = this.$refs.canvas as HTMLCanvasElement;
    // const containerWidth = container.clientWidth || window.innerWidth;

    // // 更新canvas尺寸
    // canvas.width = containerWidth;
    // canvas.style.width = `${containerWidth}px`;
    // this.width = containerWidth;

    // // 重新计算布局
    // this.recalculateLayout();

    const newWidth = (this.$el as HTMLElement).clientWidth;
    if (newWidth !== this.containerWidth) {
      this.containerWidth = newWidth;
      this.width = newWidth;
      this.height = this.cavansHeight;
      this.recalculateLayout(); // 重新计算布局
    }
  };

  // 添加参数检查方法
  private isParamWarning(
    params: TankParams,
    paramName: keyof TankParams
  ): boolean {
    try {
      // 确保参数和限制都存在
      if (!params || !params[paramName]) {
        return false;
      }

      const param = params[paramName];
      const limitKey = `${paramName}Limit` as keyof TankParams;
      const limit = params[limitKey] as TankParamLimit;

      // 确保限制值存在
      if (
        !limit ||
        typeof limit.min !== 'number' ||
        typeof limit.max !== 'number'
      ) {
        return false;
      }

      // return param < limit.min || param > limit.max;

      if (
        typeof param === 'number' &&
        typeof limit.min === 'number' &&
        typeof limit.max === 'number'
      ) {
        return param < limit.min || param > limit.max;
      }
      return false;
    } catch (error) {
      console.error(
        `Error checking parameter warning for ${paramName}:`,
        error
      );
      return false;
    }
  }

  /**
   * 处理画布鼠标移动事件
   */
  private handleCanvasMouseMove(event: MouseEvent): void {
    const canvas = this.$refs.canvas as HTMLCanvasElement;
    const rect = canvas.getBoundingClientRect();

    // 计算鼠标在canvas中的实际位置
    const x = event.clientX - rect.left;
    const y = event.clientY - rect.top;

    // 查找鼠标下方的槽体
    const hoveredTank = this.config.tanks.find(tank => {
      return (
        x >= tank.position.x * this.scale &&
        x <= (tank.position.x + tank.width) * this.scale &&
        y >= tank.position.y * this.scale &&
        y <= (tank.position.y + tank.height) * this.scale
      );
    });

    if (hoveredTank) {
      this.activeTooltip = hoveredTank;
      this.tooltipStyle = {
        left: `${event.clientX + 10}px`,
        top: `${event.clientY + 10}px`
      };
    } else {
      this.activeTooltip = null;
    }
  }

  /**
   * 处理画布鼠标离开事件
   */
  private handleCanvasMouseLeave(): void {
    this.activeTooltip = null;
  }

  private handleSaveParam(updatedParams: {
    field: string;
    value: number;
    tankID: number;
  }) {
    this.$emit('update-tank', updatedParams);
  }
}
</script>

<style scoped lang="scss">
.plating-line {
  position: relative;

  canvas {
    background: #f0f2f5;
    cursor: default; // 添加鼠标样式
  }

  .tooltip {
    position: fixed;
    background: rgba(0, 0, 0, 0.85);
    color: white;
    padding: 12px;
    border-radius: 4px;
    font-size: 12px;
    pointer-events: none;
    z-index: 1000;
    min-width: 200px;
    box-shadow: 0 3px 6px rgba(0, 0, 0, 0.23);

    .tooltip-title {
      font-weight: bold;
      font-size: 14px;
      margin-bottom: 8px;
      border-bottom: 1px solid rgba(255, 255, 255, 0.2);
      padding-bottom: 6px;
    }

    .tooltip-content {
      .tooltip-item {
        margin: 6px 0;
        display: flex;
        justify-content: space-between;
        align-items: center;

        .label {
          color: rgba(255, 255, 255, 0.85);
          margin-right: 8px;
        }

        .value {
          color: #1890ff;

          .limit {
            color: rgba(255, 255, 255, 0.45);
            font-size: 11px;
            margin-left: 4px;
          }
        }

        &.param-warning {
          .value {
            color: #ff4d4f;
            font-weight: bold;
            animation: warning-flash 1s infinite;
          }
        }

        .status-working {
          color: #52c41a;
        }
        .status-idle {
          color: #1890ff;
        }
        .status-error {
          color: #ff4d4f;
        }
      }
    }
  }
}

@keyframes warning-flash {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.7;
  }
}
</style>
